package com.tongji.diy.view.component3D
{
	import com.tongji.diy.model.RoomControlPointArc;
	import com.tongji.diy.model.RoomDataVO;
	import com.tongji.diy.utils.ArcBorderUtils;
	
	import de.polygonal.ds.DListNode;
	
	import flare.basic.Scene3D;
	import flare.collisions.MouseCollision;
	import flare.core.Mesh3D;
	import flare.core.Pivot3D;
	import flare.core.Surface3D;
	import flare.materials.Material3D;
	import flare.materials.Shader3D;
	import flare.materials.filters.TextureFilter;
	import flare.system.Input3D;
	
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Vector3D;
	
	/**
	 * 
	 * @author xxj
	 * 
	 */
	
	public class RoomFloor extends Mesh3D
	{
		private var _needToUpload:Boolean = false;
		private var roomData:RoomDataVO;
		private var material:Material3D;
		
		private const N:uint = ArcBorderUtils.N;
		private const STEP:Number = ArcBorderUtils.STEP;
		
		//鼠标Collision
		private var mouseCollision:MouseCollision = new MouseCollision();
		
		public function RoomFloor(roomData:RoomDataVO, material:Material3D)
		{
			this.roomData = roomData;
			super();
			
			var shader:Shader3D = material.clone() as Shader3D;
			if(shader.filters.length > 1)
				shader.filters.pop();
			this.material = shader as Material3D;
			
			surfaces[0] = new Surface3D();
			surfaces[0].material = this.material.clone();
			surfaces[0].addVertexData( Surface3D.POSITION );
			surfaces[0].addVertexData( Surface3D.UV0 );
			surfaces[0].addVertexData( Surface3D.NORMAL );
			
			//用于计算uv的数据
			var currentNode:DListNode = roomData.roomPointList.head;
			var maxX:Number = currentNode.data.x;
			var minX:Number = currentNode.data.x;
			var maxY:Number = currentNode.data.y;
			var minY:Number = currentNode.data.y;
			currentNode = currentNode.next;
			while (currentNode != roomData.roomPointList.head)
			{
				if (currentNode.data.x > maxX)
					maxX = currentNode.data.x;
				if (currentNode.data.x < minX)
					minX = currentNode.data.x;		
				if (currentNode.data.x > maxY)
					maxY = currentNode.data.x;
				if (currentNode.data.x < minY)
					minY = currentNode.data.x;
				currentNode = currentNode.next;
			}
			var distanceX:Number = maxX - minX;
			var distanceY:Number = maxY - minY;
			
			shader = surfaces[0].material as Shader3D;
			var texFilter:TextureFilter = shader.filters[0] as TextureFilter;
			texFilter.repeatX = distanceX/150;
			texFilter.repeatY = distanceY/150;
			
			var index:uint = 0;
			var floorX:Number;
			var floorY:Number;
			var floorU:Number;
			var floorV:Number;
			var floorIndexVector:Vector.<uint> = new Vector.<uint>;
			var floorvertexVector:Vector.<Point> = new Vector.<Point>;
			while (1)
			{
				currentNode.data.floor = this;
				floorX = currentNode.data.x;
				floorY = currentNode.data.y;
				floorU = (floorX - minX) / distanceX;
				floorV = (floorY - minY) / distanceY;
				surfaces[0].vertexVector.push(floorX, 0, floorY, floorU, 1 - floorV, 0, 1, 0);
				floorIndexVector.push(index);
				floorvertexVector.push(new Point(floorX,floorY));
				currentNode = currentNode.next;
				index++;
				if (currentNode == roomData.roomPointList.head)
					break;
			}
			
			var removeable:Boolean;
			for (var i:uint = 1; i < floorIndexVector.length - 2; i++)
			{
				if (isClockwise(surfaces[0].vertexVector[8*floorIndexVector[i - 1]], surfaces[0].vertexVector[8*floorIndexVector[i - 1]+2],
					surfaces[0].vertexVector[8*floorIndexVector[i]],surfaces[0].vertexVector[8*floorIndexVector[i]+2],
					surfaces[0].vertexVector[8*floorIndexVector[i+1]], surfaces[0].vertexVector[8*floorIndexVector[i+1]+2]))
				{
					removeable = true;
					if (floorIndexVector.length > 4)
					{
						for (var k:int = i + 2; k != i - 2 && k != i - 2 + floorIndexVector.length; k++)
						{
							if (k >= floorIndexVector.length)
								k -= floorIndexVector.length;
							var aaa:int = k;
							if (k + 1 >= floorIndexVector.length)
								k -= floorIndexVector.length;
							var bbb:int = k + 1;
							if (isIntersect(new Point(floorvertexVector[i - 1].x, floorvertexVector[i - 1].y), new Point(floorvertexVector[i + 1].x, floorvertexVector[i + 1].y), new Point(floorvertexVector[aaa].x, floorvertexVector[aaa].y), new Point(floorvertexVector[bbb].x, floorvertexVector[bbb].y)))
								removeable = false;
						}
					}
					else
					{
						var ccc:int = i + 1;
						if (ccc >= floorIndexVector.length)
							ccc -= floorIndexVector.length;
						var ddd:int = i + 2;
						if (ddd >= floorIndexVector.length)
							ddd -= floorIndexVector.length;
						var eee:int = i + 3;
						if (eee >= floorIndexVector.length)
							eee -= floorIndexVector.length;
						if (!isClockwise(floorvertexVector[ccc].x, floorvertexVector[ccc].y, floorvertexVector[ddd].x, floorvertexVector[ddd].y, floorvertexVector[eee].x, floorvertexVector[eee].y))
						{
							removeable = false;
						}
					}
					if (removeable)
					{
						surfaces[0].indexVector.push(floorIndexVector[i - 1],floorIndexVector[i],floorIndexVector[i + 1]);
						floorIndexVector.splice(i,1);
						floorvertexVector.splice(i,1);
						i = 0;
					}
				}
			}
			if (floorIndexVector.length == 4)
			{
				surfaces[0].indexVector.push(floorIndexVector[1],floorIndexVector[2],floorIndexVector[3]);
				floorIndexVector.splice(2,1);
				floorvertexVector.splice(2,1);
			}
			
			surfaces[0].indexVector.push(floorIndexVector[0],floorIndexVector[1],floorIndexVector[2]);
			_needToUpload = true;
		}
		
		public function refresh():void
		{
			mouseCollision.removeCollisionWith(this);
			
			surfaces[0].dispose()
			surfaces[0] = new Surface3D();
			surfaces[0].material = material;
			surfaces[0].addVertexData( Surface3D.POSITION );
			surfaces[0].addVertexData( Surface3D.UV0 );
			surfaces[0].addVertexData( Surface3D.NORMAL );
			surfaces[0].vertexVector = new Vector.<Number>;
			surfaces[0].indexVector = new Vector.<uint>;
			
			//用于计算uv的数据
			var currentNode:DListNode = roomData.roomPointList.head;
			var maxX:Number = currentNode.data.x;
			var minX:Number = currentNode.data.x;
			var maxY:Number = currentNode.data.y;
			var minY:Number = currentNode.data.y;
			currentNode = currentNode.next;
			while (currentNode != roomData.roomPointList.head)
			{
				if (currentNode.data.x > maxX)
					maxX = currentNode.data.x;
				if (currentNode.data.x < minX)
					minX = currentNode.data.x;		
				if (currentNode.data.x > maxY)
					maxY = currentNode.data.x;
				if (currentNode.data.x < minY)
					minY = currentNode.data.x;
				currentNode = currentNode.next;
			}
			var distanceX:Number = maxX - minX;
			var distanceY:Number = maxY - minY;
			
			var shader:Shader3D = surfaces[0].material as Shader3D;
			var texFilter:TextureFilter = shader.filters[0] as TextureFilter;
			texFilter.repeatX = distanceX/150;
			texFilter.repeatY = distanceY/150;
			
			var index:uint = 0;
			var floorX:Number;
			var floorY:Number;
			var floorU:Number;
			var floorV:Number;
			var floorIndexVector:Vector.<uint> = new Vector.<uint>;
			var floorvertexVector:Vector.<Point> = new Vector.<Point>;
			do
			{
				currentNode.data.floor = this;
				if(currentNode.next.data is RoomControlPointArc)
				{
					currentNode.next.data.floor = this;
					var sP:Point = new Point(currentNode.data.x,currentNode.data.y);
					var cP:Point = new Point(currentNode.next.data.x,currentNode.next.data.y);
					var eP:Point = new Point(currentNode.next.next.data.x,currentNode.next.next.data.y);
					for (var j:uint = 0; j<uint(1.00/STEP)-1; j++)
					{
						var p:Point = new Point();
						floorX = sP.x*ArcBorderUtils.bez(N,0,j*STEP)+cP.x*ArcBorderUtils.bez(N,1,j*STEP)+eP.x*ArcBorderUtils.bez(N,2,j*STEP);
						floorY = sP.y*ArcBorderUtils.bez(N,0,j*STEP)+cP.y*ArcBorderUtils.bez(N,1,j*STEP)+eP.y*ArcBorderUtils.bez(N,2,j*STEP);
						floorU = (floorX - minX) / distanceX;
						floorV = (floorY - minY) / distanceY;
						surfaces[0].vertexVector.push(floorX, 0, floorY, floorU, 1 - floorV, 0, 1, 0);
						floorIndexVector.push(index);
						floorvertexVector.push(new Point(floorX,floorY));
						index++;
					}
					currentNode = currentNode.next.next;
				}
				else
				{
					floorX = currentNode.data.x;
					floorY = currentNode.data.y;
					floorU = (floorX - minX) / distanceX;
					floorV = (floorY - minY) / distanceY;
					surfaces[0].vertexVector.push(floorX, 0, floorY, floorU, 1 - floorV, 0, 1, 0);
					floorIndexVector.push(index);
					floorvertexVector.push(new Point(floorX,floorY));
					index++;
					currentNode = currentNode.next;
				}
			}	
			while (currentNode != roomData.roomPointList.head)
				
			var removeable:Boolean;
			for (var i:int = 0; i < floorIndexVector.length; i++)
			{
				if (isClockwise(surfaces[0].vertexVector[8*floorIndexVector[last(i)]], surfaces[0].vertexVector[8*floorIndexVector[last(i)]+2],
					surfaces[0].vertexVector[8*floorIndexVector[i]],surfaces[0].vertexVector[8*floorIndexVector[i]+2],
					surfaces[0].vertexVector[8*floorIndexVector[next(i)]], surfaces[0].vertexVector[8*floorIndexVector[next(i)]+2])
					&& floorIndexVector.length >4)
				{
					removeable = true;
					for (var k:int = next(next(i)); k != last(last(i)) ; k=next(k))
					{
						var aaa:int = k;
						var bbb:int = next(k);
						if (isIntersect(new Point(floorvertexVector[last(i)].x, floorvertexVector[last(i)].y), new Point(floorvertexVector[next(i)].x, floorvertexVector[next(i)].y), new Point(floorvertexVector[aaa].x, floorvertexVector[aaa].y), new Point(floorvertexVector[bbb].x, floorvertexVector[bbb].y)))
							removeable = false;
					}
					if (removeable)
					{
						surfaces[0].indexVector.push(floorIndexVector[last(i)],floorIndexVector[i],floorIndexVector[next(i)]);
						floorIndexVector.splice(i,1);
						floorvertexVector.splice(i,1);
						i = -1;
					}
				}
			}
			
			if (isSame(
				new Point(surfaces[0].vertexVector[8*floorIndexVector[1]], surfaces[0].vertexVector[8*floorIndexVector[1]+2]),
				new Point(surfaces[0].vertexVector[8*floorIndexVector[3]], surfaces[0].vertexVector[8*floorIndexVector[3]+2]),
				new Point(surfaces[0].vertexVector[8*floorIndexVector[0]], surfaces[0].vertexVector[8*floorIndexVector[0]+2]),
				new Point(surfaces[0].vertexVector[8*floorIndexVector[2]], surfaces[0].vertexVector[8*floorIndexVector[2]+2])
				))
			{
				surfaces[0].indexVector.push(floorIndexVector[0],floorIndexVector[1],floorIndexVector[2]);
				floorIndexVector.splice(1,1);
				floorvertexVector.splice(1,1);
			}	
			else
			{
				surfaces[0].indexVector.push(floorIndexVector[1],floorIndexVector[2],floorIndexVector[3]);
				floorIndexVector.splice(2,1);
				floorvertexVector.splice(2,1);
			}
			surfaces[0].indexVector.push(floorIndexVector[0],floorIndexVector[1],floorIndexVector[2]);
			surfaces[0].upload(this.scene)
			
			this.updateBoundings();
			mouseCollision.addCollisionWith(this);
			
			function next (i:int):int
			{
				var next:int = i+1;
				if (next>=floorIndexVector.length)
					next -= floorIndexVector.length;
				if (next<0)
					next += floorIndexVector.length;
				return next;
			}
			
			function last (i:int):int
			{
				var last:int = i-1;
				if (last>=floorIndexVector.length)
					last -= floorIndexVector.length;
				if (last<0)
					last += floorIndexVector.length;
				return last;
			}
		}
		
		
		private function isClockwise(x0:Number, y0:Number, x1:Number, y1:Number, x2:Number, y2:Number):Boolean
		{
			if (x0 * y1 + x1 * y2 + x2 * y0 - x1 * y0 - x2 * y1 - x0 * y2 <= 0)
				return true;
			else
				return false;
		}
		
		private function isSame(startPoint:Point, endPoint:Point, pPoint:Point, qPoint:Point):int
		{
			var dx:Number = endPoint.x - startPoint.x;  
			var dy:Number = endPoint.y - startPoint.y;  
			var dx1:Number = pPoint.x - startPoint.x;  
			var dy1:Number = pPoint.y - startPoint.y;  
			var dx2:Number = qPoint.x - endPoint.x;  
			var dy2:Number = qPoint.y - endPoint.y;  
			return ((dx * dy1 - dy * dx1) * (dx * dy2 - dy * dx2) > 0 ? 1 : 0);  
		}
		
		private function isIntersect(startPoint:Point, endPoint:Point, pPoint:Point, qPoint:Point):int
		{
			return (isSame(startPoint, endPoint, pPoint, qPoint)==0 && 
				　　isSame(pPoint, qPoint, startPoint, endPoint)==0) ? 1 : 0;
		}
		
		override public function upload(scene:Scene3D = null, force:Boolean = false, includeChildren:Boolean = true ):Boolean
		{
			_needToUpload = false;
			
			if ( super.upload( scene, force, includeChildren ) == false ) return false;
			
			return true;
		}
		
		public override function draw( includeChildren:Boolean = false ):void 
		{
			if ( _needToUpload && scene ) upload( scene );
			
			if ( _needToUpload ) return;
			
			super.draw( includeChildren );
		}
		
	}
}